package com.onesports.intelligent.k12.polarlight.security;

import com.onesports.intelligent.k12.polarlight.cache.RedisTokenProvider;
import com.onesports.intelligent.k12.polarlight.common.constant.HeaderConstants;
import com.onesports.intelligent.k12.polarlight.common.utils.ResultUtil;
import com.onesports.intelligent.k12.polarlight.constant.SystemCodeConstants;
import com.onesports.intelligent.k12.polarlight.security.jwt.JwtTokenProvider;
import com.onesports.intelligent.k12.polarlight.service.operation.OrganizationService;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHeaders;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Filters incoming requests and installs a Spring Security principal if a header corresponding to a valid user is
 * found.
 *
 * @author aj
 */
@Slf4j
public class TokenAuthenticationFilter extends OncePerRequestFilter {

    private final JwtTokenProvider jwtTokenProvider;
    private final RedisTokenProvider redisTokenProvider;
    private final AuthenticationEntryPoint authenticationEntryPoint;

    public TokenAuthenticationFilter(JwtTokenProvider jwtTokenProvider,
                                     RedisTokenProvider redisTokenProvider,
                                     AuthenticationEntryPoint authenticationEntryPoint) {
        this.jwtTokenProvider = jwtTokenProvider;
        this.redisTokenProvider = redisTokenProvider;
        this.authenticationEntryPoint = authenticationEntryPoint;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        String clientCode = request.getHeader(HeaderConstants.ORIGIN_CLIENT_CODE);
        if (StringUtils.hasText(clientCode)) {
            String token = resolveToken(request);
            if (StringUtils.hasText(token)) {
                boolean isRedis = true;
                if (clientCode.startsWith(SystemCodeConstants.WX)
                        && !token.startsWith(RedisTokenProvider.TOKEN_PREFIX_COACH)) {
                    isRedis = false;
                }
                if (isRedis) {
                    //TODO 异常改造成顶层处理的方式
                    try {
                        Authentication authentication = redisTokenProvider.getAuthentication(token);
                        if (authentication != null) {
                            DomainUserDetails principal = (DomainUserDetails) authentication.getPrincipal();
                            redisTokenProvider.refreshExpiration(token,principal.getCurrent());
                            SecurityContextHolder.getContext().setAuthentication(authentication);
                        }
                    } catch (OrganizationNotActivatedException e) {
                        SecurityContextHolder.clearContext();
                        this.authenticationEntryPoint.commence(request, httpServletResponse, e);
                        return;
                    }

                } else {
                    if (jwtTokenProvider.validateToken(token)) {
                        Authentication authentication = jwtTokenProvider.getAuthentication(token);
                        SecurityContextHolder.getContext().setAuthentication(authentication);
                    }
                }
            }
        } else {
            log.warn("请求参数异常：ORIGIN_CLIENT_CODE is null");
        }

        filterChain.doFilter(request, httpServletResponse);
    }


    private String resolveToken(HttpServletRequest request) {
        String bearerToken = request.getHeader(HttpHeaders.AUTHORIZATION);
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
//        String jwt = request.getParameter(AUTHORIZATION_TOKEN);
//        if (StringUtils.hasText(jwt)) {
//            return jwt;
//        }
        return null;
    }
}
